//
//  PMSlideJoint.m
//  PezMonkey
//
//  Created by Spence DiNicolantonio on 10/31/09.
//  Copyright 2009 Necrosoft. All rights reserved.
//

/**
 * A subclass of PMJoint for representing slide joints. PMSlideJoints are Like 
 * PMPinJoints, but have flexible anchors. A Minimum and maximum limit is used 
 * to constrain the anchors freedom. These limits define the minimum and maximum 
 * distance that a joint anchor can slide from the set anchor point.
 */

#import "PMSlideJoint.h"
#import "PMBody.h"


@implementation PMSlideJoint


#pragma mark -
#pragma mark Init

/**
 * Returns a PMPinJoint object initialized by anchoring two given rigid bodys at 
 * their center of gravity, with a given minimum and maximum slide limit.
 */
- (id)initWithBodyA:(PMBody *)aBody bodyB:(PMBody *)otherBody minLimit:(PMFloat)min maxLimit:(PMFloat)max {
	return [self initWithAnchor:PMVectZero 
						onBodyA:aBody 
						 anchor:PMVectZero 
						onBodyB:otherBody
					   minLimit:min
					   maxLimit:max];
}

/**
 * Returns a PMPinJoint object initialized by anchoring two given rigid bodys at 
 * given positions reletive to the corresponding body's center of gravity. Slide
 * limits are set to a given minimum and maximum value.
 */
- (id)initWithAnchor:(PMAnchor)anchorA onBodyA:(PMBody *)aBody anchor:(PMAnchor)anchorB onBodyB:(PMBody *)otherBody minLimit:(PMFloat)min maxLimit:(PMFloat)max { 
	if (![super init])
		return nil;
	
	// allocate and initialize cpJoint
	joint = cpSlideJointNew(aBody.cpBody, otherBody.cpBody, anchorA, anchorB, min, max);
	
	// set body references
	self.bodyA = aBody;
	self.bodyB = otherBody;
	
	return self;
}


#pragma mark -
#pragma mark Getters

/**
 * Returns the receiver's joint anchor position for bodyA.
 */
- (PMAnchor)anchorA {
	return ((cpSlideJoint *) joint)->anchr1;
}

/**
 * Returns the receiver's joint anchor position for bodyB.
 */
- (PMAnchor)anchorB {
	return ((cpSlideJoint *) joint)->anchr2;
}

/**
 * Returns the receiver's joint anchor position for the body corresponding to the 
 * given key. Returns PMVectZero if there is no body/anchor for the given key.
 */
- (PMAnchor)anchorForBodyWithKey:(PMJointBodyKey)bodyKey {
	switch (bodyKey) {
		case PMJointBodyKeyA:
			return [self anchorA];
		case PMJointBodyKeyB:
			return [self anchorB];
		default:
			return PMVectZero;
	}
}

/**
 * Returns the receivers minimum slide limit.
 */
- (PMFloat)minLimit {
	return ((cpSlideJoint *) joint)->min;
}

/**
 * Returns the receivers maximum slide limit.
 */
- (PMFloat)maxLimit {
	return ((cpSlideJoint *) joint)->max;
}


#pragma mark -
#pragma mark Setters

/**
 * Sets the joint anchor position of the receiver's bodyA to a given point relative
 * the the body's center of gravity.
 */
- (void)setAnchorA:(PMAnchor)anchor {
	((cpSlideJoint *) joint)->anchr1 = anchor;
}

/**
 * Sets the joint anchor position of the receiver's bodyB to a given point relative
 * the the body's center of gravity.
 */
- (void)setAnchorB:(PMAnchor)anchor {
	((cpSlideJoint *) joint)->anchr2 = anchor;
}

/**
 * Sets the joint anchor position of the receiver's body corresponding to the given
 * key, to a given point relative the the body's center of gravity.
 */
- (void)setAnchor:(PMAnchor)anchor ForBodyWithKey:(PMJointBodyKey)bodyKey {
	switch (bodyKey) {
		case PMJointBodyKeyA:
			return [self setAnchorA:anchor];
		case PMJointBodyKeyB:
			return [self setAnchorB:anchor];
	}
}

/**
 * Sets the receiver's minimum slide limit to a given value.
 */
- (void)setMinLimit:(PMFloat)limit {
	((cpSlideJoint *) joint)->min = limit;
}

/**
 * Sets the receiver's maximum slide limit to a given value.
 */
- (void)setMaxLimit:(PMFloat)limit {
	((cpSlideJoint *) joint)->max = limit;
}

@end
